const dfS7List = [];

const doList = []; // writeList

let doPending = false;

let s7 = null;

class dfS7 {
  options = null;

  reNum = 5;

  sock = null;

  sOptions = null;

  // sockPing = false;

  isInit = false;

  num = 0;

  overTime = 100;

  // pending = false;

  name = null;

  isOnLine = false;

  connectType = null;

  plcId = null;

  addressObj = null;

  readList = [];

  connectReadTime = 100;

  readErrorNum = 0;

  readTime = null;

  constructor(options) {
    this.options = options;

    // const { s7Options = null } = options;

    if (options) {
      const {
        connectReadTime = 100,
        connectOverTime = 5000,
        reConnectNum = 5,
        name = null,
        plcId = null,
        addressObj = null,
        addressList = [],
      } = options;

      this.isInit = true;

      if (!this.sOptions) {
        this.sOptions = options;
      }

      if (connectOverTime) {
        this.overTime = connectOverTime;
      }

      if (reConnectNum) {
        this.reNum = reConnectNum;
      }

      if (name) {
        this.name = name;
      }

      if (plcId) {
        this.plcId = plcId;
      }

      if (addressObj) {
        this.addressObj = addressObj;
      }

      if (addressList && addressList.length) {
        this.readList = addressList;
      }

      if (connectReadTime) {
        this.connectReadTime = connectReadTime;
      }

      this.initFn(this.options);

      // dfS7List.push(this);
    } else {
      throw new Error('请传入配置参数');
    }
  }

  initFn(options = this.options) {
    const { slot = 0, rack = 0, port = null, host = null } = options;

    const nodes7 = require('nodes7');

    this.sock = new nodes7();

    this.sock.initiateConnection({ port, host, rack, slot, debug: false }, async (err) => {
      if (typeof err !== 'undefined') {
        // We have an error. Maybe the PLC is not reachable.
        console.log(err);

        if (!this.isInit) {
          this.reConnectFn(this.options);
        } else {
          if (this.num <= this.reNum) {
            this.num++;

            setTimeout(() => {
              this.reConnectFn(this.options, true);
            }, 1000);
          }
        }

        // console.log(this.isInit);

        // console.log(this.num);

        // console.log(this.reNum);

        return;
        // process.exit();
      }

      this.isOnLine = true;

      process.send({
        type: 'isOnline',
        success: true,
        name: this.name,
      });

      if (this.addressObj) {
        this.sock.setTranslationCB((tag) => {
          return this.addressObj[tag];
        });

        if (this.readList) {
          const readList = this.readList;

          if (!this.readList.length) {
            for (const i in this.addressObj) {
              readList.push(i);
            }
          }

          try {
            await this.sock.addItems(readList);

            this.readFn();
          } catch (e) {
            console.log(e);
          }
        }
      }

      // this.sock.dropConnection(e => {
      //   console.log('错误',e)
      //   if (!this.isInit) {
      //     this.reConnectFn(this.sOptions);
      //   } else {
      //     if (this.num <= this.reNum) {
      //       this.num++;

      //       setTimeout(() => {
      //         this.reConnectFn(this.sOptions, true);
      //       }, 1000);
      //     }
      //   }
      // });
    });
  }

  reConnectFn(options = this.options, isConnent = false) {
    if (!this.isInit || isConnent) {
      if (!this.isInit) {
        this.isInit = true;
      }

      this.sock = null;

      this.initFn(options);

      process.send({
        type: 'isOnline',
        success: false,
        name: this.name,
      });

      this.isOnLine = false;
    }
  }

  async readFn() {
    // console.log(this)
    if (this.readTime) {
      clearTimeout(this.readTime);

      this.readTime = null;
    }

    if (this.sock) {
      let data = null;

      try {
        this.sock.readAllItems((anythingBad, values) => {
          if (anythingBad) {
            console.log('SOMETHING WENT WRONG READING VALUES!!!!');

            data = false;

            // this.num = 0;

            // this.reConnectFn(this.sOptions,true);

            console.log('数据有误', values);

            process.send({
              type: 'read',
              success: false,
              name: this.name,
              err: `读取失败,数据有误,SOMETHING WENT WRONG READING VALUES!!!!`,
              msg: values,
            });

            this.readErrorNum++;

            if (this.readErrorNum >= this.reNum) {
              this.num = 0;

              this.readErrorNum = 0;

              this.reConnectFn(this.sOptions, true);

              return;
            }
          } else {
            data = values;

            process.send({
              type: 'read',
              success: true,
              name: this.name,
              data,
            });

            if (this.readErrorNum) {
              this.readErrorNum = 0;
            }

            // console.log(values);
          }

          this.readTime = setTimeout(() => {
            this.readFn();
          }, this.connectReadTime || 100);
        });
      } catch (e) {
        console.log(e);
      }

      // sock.resume();
      // console.log(data)
    } else {
      return false;
    }
  }

  async commandFn(obj, writeId = null) {
    if (this.sock && obj) {
      const keyList = [];

      const valueList = [];

      let writeStatus = null;

      for (const i in obj) {
        keyList.push(i);

        valueList.push(obj[i]);
      }

      console.log(obj);

      console.log(keyList);

      console.log(valueList);

      this.sock.writeItems(keyList, valueList, (anythingBad) => {
        if (anythingBad) {
          console.log('SOMETHING WENT WRONG WRITING VALUES!!!!');

          writeStatus = false;

          process.send({
            type: 'write',
            success: false,
            name: this.name,
            err: `写入失败`,
            msg: 'SOMETHING WENT WRONG WRITING VALUES!!!!',
            id: writeId,
          });
        } else {
          writeStatus = true;

          process.send({
            type: 'write',
            success: true,
            name: this.name,
            id: writeId,
          });
        }
      });

      // sock.resume();
      // console.log(data)
      return new Promise((resolve) => {
        let num = 0;

        let sockPingCommand = setInterval(async () => {
          num += 100;

          if (writeStatus !== null || num >= this.overTime) {
            clearInterval(sockPingCommand);

            // this.pending = false;

            resolve(!!writeStatus);
          }
        }, 100);
      });
    } else {
      return false;
    }
  }

  async setReadFn(list = [], type = 'add') {
    if (this.sock && list && list.length) {
      if (type === 'add') {
        this.sock.addItems(list);
      }

      if (type === 'remove') {
        this.sock.removeItems(list);
      }

      return true;
    } else {
      return false;
    }
  }

  closeSockFn() {
    if (this.sock) {
      this.sock.close();
    }
  }
}

const getDataFn = async (connectReadTime) => {
  // if (!obj) {
  //   throw new Error('请传入正确获取数据的参数');
  // }
  const { isOnLine = false, sock = null, readFn = null } = s7 || {};

  if (sock && isOnLine && readFn) {
    const res = await s7.readFn();

    if (typeof res === 'object') {
      // modbusStore.updateNewData(res);

      process.send({
        type: 'read',
        success: true,
        name,
        data: res,
      });

      // uploadMessageFn({ data, moduleMark: 'ModuleJSON' });
    }

    // message.success(t('common.tipMsg.writeSuccess'));
  }

  setTimeout(() => {
    getDataFn();
  }, connectReadTime);

  return true;
};

const initFn = async (data) => {
  if (data) {
    const { options } = data;

    s7 = new dfS7({
      ...options,
      host: options.ip ? options.ip : options.host,
    });

    dfS7List.push(s7);
  }
};

const deleteFn = ()=>{
  console.log('关闭')

  // if(intervalTime){
  //   clearInterval(intervalTime);

  //   intervalTime = null;
  // }

  process.exit();

  // if (s7 && s7.closeSockFn) {
  //   // s7.closeSockFn();
  //   process.exit();
  // }
}

const writeFn = async obj => {
  const { isOnLine = false, sock = null } = s7 || {};

  // console.log(obj)

  if (isOnLine && sock && obj) {
    const { writeObj=null ,id=null} = obj;

    if (doPending) {
      doList.push(obj);

      return false;
    } else {
      doPending = true;
    }

    const res = await s7.commandFn(writeObj, id);

    doPending = false;

    if (res === false) {

      console.log(res);
      // fn && fn(res);

      // return false;
    }

    if (doList && doList.length) {
      writeFn(doList[0]);

      doList.splice(0, 1);
    }
  }
};

const connectFn = () => {
  for (const item of dfS7List) {
    const {
      isOnLine = false,
      num = 0,
      reNum = 0,
      reConnectFn = null,
      sOptions = null,
      name = null
    } = item;

    if (!isOnLine && reConnectFn && sOptions && num > reNum) {
      item.num = 0;

      console.log(name + '重连');

      setTimeout(() => {
        item.reConnectFn(sOptions, true);
      }, 1000);
    }
  }
};

process.on('message', obj => {
  // console.log(obj);

  if (obj) {
    const { type = null, data = null } = obj;

    switch (type) {
      case 'init':
        initFn(obj);
        break;

      case 'write':
        writeFn(data);
        break;

      case 'connect':
        connectFn();
        break;

      case 'delete':
        deleteFn();
        break;

      default:
        break;
    }
  }
});
